﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TestOnlineProject.Models.Entities;
using System.Transactions;
using System.Data.Objects;
using TestOnlineProject.Common;


namespace TestOnlineProject.Models.DataAccess
{
    public class QuestionDAO
    {
        private TestOnlineDBEntities db = new TestOnlineDBEntities();

        public List<Question> Select()
        {
            try
            {
                var questions = db.Questions.ToList();
                return questions;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public Question SelectByQuestionId(int questionId)
        {
            try
            {
                var question = db.Questions.Where(q => q.QuestionId == questionId).FirstOrDefault();
                return question;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public List<Question> SelectBySubjectId(int subjectId)
        {
            try
            {
                var questions = db.Questions.Where(q => q.SubjectId == subjectId).ToList();
                return questions;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int Update(Question question)
        {
            try
            {
                using (TransactionScope tran = new TransactionScope())
                {
                    TestOnlineDBEntities db2 = new TestOnlineDBEntities();

                    var qu = db.Questions.Where(q => q.QuestionId == question.QuestionId).FirstOrDefault();

                    // Delete UserAnswers.
                    foreach (var a in qu.Answers)
                    {
                        a.UserAnswers.ToList().ForEach(db.DeleteObject);
                    }

                    // Delete old answers.
                    qu.Answers.ToList().ForEach(db.DeleteObject);

                    // Delete old matches.
                    qu.Matches.ToList().ForEach(db.DeleteObject);

                    // Insert new answers.
                    for (var i = 0; i < question.Answers.Count; i++)
                    {
                        db.Answers.AddObject(new Answer
                        {
                            QuestionId = question.Answers.ToList()[i].QuestionId,
                            Content = question.Answers.ToList()[i].Content,
                            Grade = question.Answers.ToList()[i].Grade
                        });
                    }

                    if (question.Matches != null && question.Matches.Count > 0)
                    {
                        // Insert new matches.
                        for (var i = 0; i < question.Matches.Count; i++)
                        {
                            db.Matches.AddObject(new Match
                            {
                                QuestionId = question.Matches.ToList()[i].QuestionId,
                                Content = question.Matches.ToList()[i].Content,
                            });
                        }
                    }

                    // Set values.
                    //qu.SectionId = question.SectionId;
                    qu.Title = question.Title;
                    qu.Content = question.Content;
                    qu.Explanation = question.Explanation ?? null;
                    qu.LastEditedTime = question.LastEditedTime;
                    int result = db.SaveChanges(SaveOptions.DetectChangesBeforeSave);

                    // Update answer matchId.
                    if (question.Matches != null && question.Matches.Count > 0)
                    {
                        int matchPos = 0;
                        foreach (var a in qu.Answers.OrderBy(i => i.AnswerId))
                        {
                            a.MatchId = qu.Matches.OrderBy(i => i.MatchId).ToList()[matchPos].MatchId;
                            matchPos++;
                        }
                        db2.SaveChanges(SaveOptions.DetectChangesBeforeSave);
                    }

                    tran.Complete();
                    db.AcceptAllChanges();
                    db2.AcceptAllChanges();

                    return result;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int Insert(Question question)
        {
            try
            {
                // Insert question.
                db.Questions.AddObject(question);
                int result = db.SaveChanges();

                // Update answer matchId.
                int matchPos = 0;
                if (question.Matches != null && question.Matches.Count > 0)
                {
                    foreach (var a in question.Answers)
                    {
                        a.MatchId = question.Matches.ToList()[matchPos].MatchId;
                        matchPos++;
                    }
                    db.SaveChanges();
                }
                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        //import
        public List<Question> Insert(List<Question> questions, int createrId)
        {
            List<Question> importedQuestion = new List<Question>();
            try
            {
                for (int i = 0; i < questions.Count; i++)
                {
                    questions[i].UserId = createrId;
                    CheckDublicateQuestion check = new CheckDublicateQuestion();
                    var exist = check.CheckDublicate(ListAllQuestion(questions[i]), questions[i]);
                    if (exist == false)
                    {
                        this.db.Questions.AddObject(questions[i]);
                        importedQuestion.Add(questions[i]);
                        
                    }
                }
                this.db.SaveChanges();
                return importedQuestion;
            }
            catch (Exception)
            {
                return null;
            }

        }
        public int Deactivate(int questionId)
        {
            try
            {
                var question = db.Questions.Where(q => q.QuestionId == questionId).FirstOrDefault();
                question.IsActivated = false;
                int result = db.SaveChanges();
                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int Activate(int questionId)
        {
            try
            {
                var question = db.Questions.Where(q => q.QuestionId == questionId).FirstOrDefault();
                question.IsActivated = true;
                int result = db.SaveChanges();
                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int Delete(int questionId)
        {
            try
            {
                using (TransactionScope tran = new TransactionScope())
                {
                    TestOnlineDBEntities db2 = new TestOnlineDBEntities();
                    TestOnlineDBEntities db3 = new TestOnlineDBEntities();

                    var question = db.Questions.Where(q => q.QuestionId == questionId).FirstOrDefault();

                    // Delete Reports.
                    question.Reports.ToList().ForEach(db.DeleteObject);

                    // Delete TestQuestions.
                    question.TestQuestions.ToList().ForEach(db.DeleteObject);

                    // Delete UserAnswers.
                    question.UserAnswers.ToList().ForEach(db.DeleteObject);

                    //Delete Answers.
                    question.Answers.ToList().ForEach(db.DeleteObject);

                    // Delete Matches.
                    question.Matches.ToList().ForEach(db.DeleteObject);

                    // Delete SectionQuestions.
                    question.SectionQuestions.ToList().ForEach(db.DeleteObject);

                    // Delete questions.
                    db.Questions.DeleteObject(question);

                    int result = db.SaveChanges(SaveOptions.DetectChangesBeforeSave);

                    // Delete empty Test with UserTests.
                    var emptyTests = db2.Tests.Where(t => t.TestQuestions.Count == 0).ToList();
                    foreach (var t in emptyTests)
                    {
                        foreach (var ut in t.UserTests)
                        {
                            ut.UserAnswers.ToList().ForEach(db2.DeleteObject);
                        }
                        t.UserTests.ToList().ForEach(db2.DeleteObject);
                    }
                    emptyTests.ForEach(db2.DeleteObject);
                    db2.SaveChanges(SaveOptions.DetectChangesBeforeSave);

                    // Delete empty UserTests.
                    db3.UserTests.Where(ut => ut.TestId == null && ut.UserAnswers.Count == 0).ToList().ForEach(db3.DeleteObject);
                    db3.SaveChanges(SaveOptions.DetectChangesBeforeSave);

                    tran.Complete();

                    db.AcceptAllChanges();
                    db2.AcceptAllChanges();
                    db3.AcceptAllChanges();

                    return result > 0 ? 1 : 0;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int DeleteByUserId(int userId)
        {
            try
            {
                var result = 0;
                var questions = db.Questions.Where(x => x.UserId == userId).ToList();
                foreach (var question in questions)
                {
                    var matches = db.Matches.Where(x => x.QuestionId == question.QuestionId).ToList();
                    foreach (var match in matches)
                    {
                        db.Matches.DeleteObject(match);
                    }

                    var answers = db.Answers.Where(x => x.QuestionId == question.QuestionId).ToList();
                    foreach (var answer in answers)
                    {
                        db.Answers.DeleteObject(answer);
                    }
                    db.Questions.DeleteObject(question);
                    result += db.SaveChanges();
                }
                return result;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        public  List<Question> ListImportedQuestion(int subjectId, int userId, int page = 1, int size = 10)
        {
            try
            {
                var lastestImportQuestionDatetime = (from q in this.db.Questions
                                                     where q.SubjectId == subjectId && q.UserId == userId
                                                     select q.CreatedTime).Max();
                var questions = (from data in this.db.Questions
                                 where data.SubjectId == subjectId && data.UserId == userId && data.CreatedTime == lastestImportQuestionDatetime
                                 select data).OrderBy(c => c.QuestionId).ToList();
                return questions;
            }
            catch (Exception ex)
            {
                return new List<Question>();
            }
        }
        public List<Question> ListAllQuestion(Question question)
        { 
            var listQuestion = (from q in this.db.Questions
                                where q.Content == question.Content
                                select q).ToList();
            return listQuestion;
        }
    }
}